home account info subscribe login search FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

Bug Proofing Visual Basic: A Guide to Error Handling and Prevention
(Publisher: John Wiley & Sons, Inc.)
Author(s): Rod Stephens
ISBN: 0471323519
Publication Date: 11/01/98

Search this book:
 
Previous Table of Contents Next


When this error occurs, the error handler that catches the error will probably display a message like this one:

Error -2147220504 loading the input data.
Error -2147220504 opening the input file.

Leave the formatting to the routine that actually records the error or presents the message to the user.

Define Error Constants

Microsoft says normal error messages lie in the range of 1 to 65,535. They reserve the range 1 to 1000 for use by Visual Basic, and some of the values between 31,000 and 31,037 are already used by Visual Basic. You can use other values to define your own error codes.

Microsoft also recommends that you define new error constants for classes by adding a value to the constant vbObjectError as in the following code:

Private Const myclassErrNoInputFile = vbObjectError + 1000

If you follow these rules, your error codes will not overlap Microsoft’s. Unfortunately, this does not guarantee that your error code will not collide with other error constants defined by other developers or libraries you use.

One method for preventing confusion is to define a base value similar to vbObjectError for your constants. Then define error codes in terms of that constant. For example, a ray-tracing package might define error codes as in the following code:

Public Const rayErrorBase = 45300
Public Const rayParametersNotSet = rayErrorBase + 1
Public Const rayInvalidSphereFormat = rayErrorBase + 2
Public Const rayLightAtEye = rayErrorBase + 3
    :

If you later discover that your error codes collide with those of another developer or library, you can quickly redefine all of the error codes by changing the error base value.

Keep Error Handlers Separate

End every error handler with Resume, Resume Next, Exit Sub/Function/Property, End Sub/Function/Property, or Err.Raise. Never allow the code to fall through from one error handler into another. This can produce some clever code, but it can produce confusion as well.

For example, the following code falls through its error handlers to close the file it has opened.

Private Sub LoadData(ByVal filename As String)
Dim fnum As Integer

    ' The file is not yet open.
    On Error GoTo FileIsClosed

    ' Open the file.
    fnum = FreeFile
    Open filename For Input As fnum

    ' The file is now open.
    On Error GoTo FileIsOpen

    ' Read the data.
        :

    ' Fall into the error handlers to close the file.
    On Error Resume Next

FileIsOpen:
    ' Close the file.
    Close fnum

FileIsClosed:
    ' Perform any final tasks.
        :

    ' Fall through to the End Sub.
End Sub

This code has a number of problems. First, it is confusing. Another developer who tries to add a new error handler would be likely to make a mistake and cause a bug. This code also does not signal its errors. Instead, it quietly continues as if nothing has gone wrong. It hides bugs that might otherwise be easy to fix.

Prevent confusion and possible bugs by keeping error handlers separate.

Understand Error Handler Scope

When a program encounters an error, Visual Basic checks to see if an error handler is presently installed in the current routine. If so, control passes to that error handler.

If no error handler is in effect, Visual Basic moves up the call stack to the calling routine to see if an error handler is currently installed there. If so, the system resumes execution at that error handler.

If no error handler is installed in the calling routine either, Visual Basic continues moving up the call stack until it finds a routine with an error handler installed. If it runs off the top of the stack before it finds an active error handler, the program crashes.

Execution of all Visual Basic code begins with either an event handler or the Main subroutine. That means you can guard against almost all errors if you place error handlers in every event handler and the Main subroutine (if the program uses one). Then, no matter where the program encounters an error, control eventually passes up through the call stack to the event handler or Main subroutine that started the code. The error handler installed at that point can handle the error.

Don’t Nest Error Handlers

Error handler code runs a little differently from other code. No other error handler can be active within another error handler’s code. In other words, an error handler cannot use On Error GoTo to define an error handler to catch its mistakes. If an error handler uses On Error GoTo, the new error handler only takes effect when the error handler finishes and returns control to the main code sequence.

This sort of thing can be very confusing. If Subroutine2 raises an error in the following code, it is not clear whether control passes to the Error1 or Error2 error handler. Control passes to Error1 if Subroutine1 ran correctly, but it passes to Error2 if Subroutine1 also generated an error.

    On Error GoTo Error1
    Subroutine1
    Subroutine2
    Exit Sub

Error1:
    On Error GoTo Error2
    MsgBox "Error1:" & Str$(Err.Number) & "." & vbCrLf & _
        Err.Description
    Resume Next

Error2:
    MsgBox "Error2:" & Str$(Err.Number) & "." & vbCrLf & _
        Err.Description
    Resume Next

Avoid this confusion by not using On Error statements within error handler code. Keep all On Error statements in the main code sequence.

Write Bugproof Error Handlers

If an error occurs while an error handler is running, Visual Basic raises the new error up the call stack to any calling routine that has an error handler defined. In that case, the original error handler loses control and cannot finish whatever it was doing. It cannot finish closing files and performing other cleanup chores. For this reason, error handler code must be as bugproof as possible.

Unfortunately, error handlers are bug prone. They are often complicated and they execute when something else has already gone wrong and the state of the system may be uncertain. Many error handlers are not adequately tested. In part that is because error handlers are usually difficult and tedious to test. Programmers also spend most of their time working under more normal conditions so they have less experience working under the strange circumstances that sometimes arise when errors occur.

To make error handlers a little safer, move risky operations into a subroutine. The subroutine can protect the error handler using its own On Error statement. Note that the subroutine must handle its errors completely. It cannot raise an error of its own. If it does, control passes out of the original error handler and moves up the call stack.

In the following code, subroutine RiskySub may generate an error. If it does, it calls subroutine LogError to write error information into a log file. LogError might fail, so it protects itself with an On Error Resume Next statement. If it does fail, LogError continues instead of raising a new error so the error handler in RiskySub does not lose control.


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-1999 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permision of EarthWeb is prohibited.